﻿using System.Linq;
using NUnit.Framework;
using StreetPacMan.Server.Facade;

namespace StreetPacMan.Server.Tests.Integ
{
    [TestFixture]
    public class GpsRunOff : BaseCleaner
    {
        [TestCase(new[] { 1, 1.00001 }, 1.00001, Description = "Normal movement, keep last location")]
        [TestCase(new double[] { 1, 2 }, 1, Description = "One jump, keep origin")]
        [TestCase(new double[] { 1, 2, 2 }, 1, Description = "One jump, consistent updates in location, keep origin")]
        [TestCase(new double[] { 1, 2, 2, 2, 2 }, 1, Description = "One jump, consistent updates in location, keep origin")]
        [TestCase(new double[] { 1, 2, 3 }, 1, Description = "Two jumps, consistent updates in locations, keep origin")]
        [TestCase(new double[] { 1, 2, 3, 3 }, 1, Description = "Two jumps, consistent updates in locations, keep origin")]
        [TestCase(new double[] { 1, 2, 1 }, 1, Description = "One jump, keep origin")]
        [TestCase(new[] { 1, 2, 1.00001 }, 1.00001, Description = "Regular movement inturrepted by jump. Ignore jump, update last location")]
        [TestCase(new[] { 1, 2, 2.00001 }, 2.00001, Description = "Movement with jump. update last location")]
        [TestCase(new[] { 1, 2, 2, 2.00001 }, 2.00001, Description = "Movement with jump. update last location")]
        public void DoServerPoll_MoveInTheRightDirection_SaveNewLocation(double[] locations, double expectedLocation)
        {
            var instance = ServerFacadeFactory.GetServerFacade();
            instance.CreateGameX("GameName");
            var pacman = instance.JoinGameX("GameName", "PacManName", PlayerRole.PacMan);

            ServerPollResult retVal = null;
            foreach (var location in locations)
            {
                retVal = instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, location, location, true));
            }

            if (retVal == null) Assert.Fail();

            Assert.AreEqual(expectedLocation, retVal.Players.Where(x => x.EntityId == pacman.PlayerId).Single().Lat);
            Assert.AreEqual(expectedLocation, retVal.Players.Where(x => x.EntityId == pacman.PlayerId).Single().Lng);
        }

        [Test]
        public void WhenRunnofIsCorrected_EventShouldBeAdded()
        {
            var instance = ServerFacadeFactory.GetServerFacade();
            instance.CreateGameX("GameName");
            var pacman = instance.JoinGameX("GameName", "PacManName", PlayerRole.PacMan);

            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 2, 2, true));
            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 3, 3, true));
            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 3.00001, 3.00001, true));
            Assert.IsTrue(instance.GetAllEventsX("GameName").Events.Any(x => x.Type == EventType.PlayerLocationCorrected));
        }

        [Test]
        public void WhenRunnofIsDetectedButUncorrected_EventShouldNotBeAdded()
        {
            var instance = ServerFacadeFactory.GetServerFacade();
            instance.CreateGameX("GameName");
            var pacman = instance.JoinGameX("GameName", "PacManName", PlayerRole.PacMan);

            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 2, 2, true));
            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 3, 3, true));
            Assert.IsFalse(instance.GetAllEventsX("GameName").Events.Any(x => x.Type == EventType.PlayerLocationCorrected));
        }

        [Test]
        public void WhenNoRunnofOccured_EventShouldNotBeAdded()
        {
            var instance = ServerFacadeFactory.GetServerFacade();
            instance.CreateGameX("GameName");
            var pacman = instance.JoinGameX("GameName", "PacManName", PlayerRole.PacMan);

            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 2, 2, true));
            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 2.00001, 2.00001, true));
            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 2.00002, 2.00002, true));
            Assert.IsFalse(instance.GetAllEventsX("GameName").Events.Any(x => x.Type == EventType.PlayerLocationCorrected));
        }

        [Test]
        public void PacManJumpsOverAppleAndStops_TheApplesInTheMiddleShouldNotBeEaten()
        {
            var instance = ServerFacadeFactory.CreateGameWithApplesOnlyAt(new[] { new InitialApple { Lat = 2, Lon = 2 }});

            instance.CreateGameX("GameName");
            var pacman = instance.JoinGameX("GameName", "PacManName", PlayerRole.PacMan);

            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 2, 1.9, true));
            var retVal = instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 2, 2.1, true));

            Assert.AreEqual(0, retVal.RemovedAppleIds.Count());
        }

        [TestCase(2, 2, true, Description = "Apple in the middle of route")]
        [TestCase(2, 2.001, true, Description = "Apple next to the x-middle of route")]
        [TestCase(2.0001, 2, true, Description = "Apple next to the y-middle of route")]
        [TestCase(2, 2.0999, true, Description = "Apple just before the edge of correction route")]
        [TestCase(2, 2.10001, true, Description = "Apple at the edge of correction route")]
        [TestCase(2, 2.10002, true, Description = "Apple AFTER at the edge of correction route, but in range of eating")]
        [TestCase(2.0001, 2.1001, true, Description = "Apple AFTER at the edge of correction route, but in range of eating, not on same x-axis")]
        [TestCase(2, 2.2, false, Description = "Apple AFTER at the edge of correction route, not in range of eating")]
        [TestCase(2, 1.8, false, Description = "Apple not on the corrected route")]
        public void PacManJumpsOverAppleAndContinuesWalkingThere_TheAppleInTheMiddleShouldBeEaten(double lat, double lon, bool shouldBeRemoved)
        {
            var instance = ServerFacadeFactory.CreateGameWithApplesOnlyAt(new[] { new InitialApple { Lat = lat, Lon = lon } });

            instance.CreateGameX("GameName");
            var pacman = instance.JoinGameX("GameName", "PacManName", PlayerRole.PacMan);

            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 2, 1.9, true));
            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 2, 2.1, true));
            var retVal = instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 2, 2.10001, true));

            Assert.AreEqual(shouldBeRemoved, retVal.RemovedAppleIds.Any());
        }

        [Test]
        public void PacManJumpsOverTwoApplesAndContinuesWalkingThere_TheApplesInTheMiddleShouldBeEaten()
        {
            var instance = ServerFacadeFactory.CreateGameWithApplesOnlyAt(new[] { new InitialApple { Lat = 2, Lon = 1.95 }, new InitialApple { Lat = 2, Lon = 2.05 } });

            instance.CreateGameX("GameName");
            var pacman = instance.JoinGameX("GameName", "PacManName", PlayerRole.PacMan);

            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 2, 1.9, true));
            instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 2, 2.1, true));
            var retVal = instance.UpdateMyWhereabouts(new ServerPollParameters(pacman.PlayerId, 2, 2.10001, true));

            Assert.AreEqual(2, retVal.RemovedAppleIds.Count());
        }


    }
}